#include <iostream>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <string>

#include "luaapi.h"
#include "sunnet.h"

using namespace std;

void luaapi::Register(lua_State *luastate)
{
    static luaL_Reg lualibs[] = {
        {"newservice", newservice},
        {"exit", killservice},
        {"send", send},
        {"write", Write},
        {"listen", Listen},
        {"close", closeconn},
        // {"self", self},
        {NULL, NULL},
    };
    luaL_newlib(luastate, lualibs);
    lua_setglobal(luastate, "sunnet"); // Pops a value from the stack and sets it as the new value of global name.
}

int luaapi::newservice(lua_State *luastate)
{
    int num = lua_gettop(luastate);
    if (lua_isstring(luastate, num) == 0)
    {
        lua_pushinteger(luastate, -1);
        return 1;
    }

    size_t len = 0;
    const char *type = lua_tolstring(luastate, 1, &len);
    char *newstr = new char[len + 1];
    // char *newstr[len + 1];
    newstr[len] = '\0';
    memcpy(newstr, type, len);
    auto t = make_shared<string>(newstr);

    uint32_t id = sunnet::inst->newservice(t);
    lua_pushinteger(luastate, id);
    return 1;
}

/**
 * ???
 * skynet 是如何在 lua 层知道自己的服务 id 的?
 */

int luaapi::killservice(lua_State *luastate)
{
    int num = lua_gettop(luastate);
    if (lua_isinteger(luastate, 1) == 0)
        return 0;
    int id = lua_tointeger(luastate, 1);
    sunnet::inst->killservice(id);
    return 0;
}

int luaapi::send(lua_State *luastate)
{
    lua_State *l = luastate;

    int num = lua_gettop(luastate);
    if (num != 3)
    {
        cout << "send fail, num error" << endl;
        return 0;
    }

    // source id
    if (lua_isinteger(l, 1) == 0)
    {
        cout << "source id is not a integer type" << endl;
        return 0;
    }

    // dest id
    if (lua_isinteger(l, 2) == 0)
    {
        cout << "destination id is not a interger type " << endl;
        return 0;
    }

    if (lua_isstring(l, 3) == 0)
    {
        cout << "send failt, arg3 error" << endl;
        return 0;
    }

    int sourceid = lua_tointeger(l, 1);
    int toid = lua_tointeger(l, 2);
    size_t len = 0;
    const char *buff = lua_tolstring(l, 3, &len);
    char *newchar = new char[len];
    memcpy(newchar, buff, len);

    auto msg = make_shared<service_msg>();
    msg->type = base_msg::TYPE::service;
    msg->source = sourceid;
    msg->buff = shared_ptr<char>(newchar);
    msg->size = len;
    sunnet::inst->send(toid, msg);
    return 0;
}

int luaapi::Write(lua_State *luastate)
{
    // 参数个数
    int num = lua_gettop(luastate);
    // 参数 1: fd
    if (lua_isinteger(luastate, 1) == 0)
    {
        lua_pushinteger(luastate, -1);
        return 1;
    }

    // 参数 2: buff
    if (lua_isstring(luastate, 2) == 0)
    {
        lua_pushinteger(luastate, -1);
        return 1;
    }

    int fd = lua_tointeger(luastate, 1);
    size_t len = 0;
    const char *buff = lua_tolstring(luastate, 2, &len);
    // 写 socket
    int r = write(fd, buff, len);

    // 写了多少字节有业务层处理
    lua_pushinteger(luastate, r);
    return 1;
}

int luaapi::Listen(lua_State *luastate)
{
    lua_State *l = luastate;
    int num = lua_gettop(l);
    if (num != 2)
    {
        lua_pushinteger(l, -1);
        return 1;
    }

    // 参数 1: port
    if (lua_isinteger(l, 1) == 0)
    {
        lua_pushinteger(l, -1);
        return 1;
    }

    // 参数 2: serviceid
    if (lua_isinteger(l, 2) == 0)
    {
        lua_pushinteger(l, -1);
        return 1;
    }

    int port = lua_tointeger(l, 1);
    int serviceid = lua_tointeger(l, 2);
    sunnet::inst->Listen(port, serviceid);

    lua_pushinteger(l, 0);
    return 1;
}

int luaapi::closeconn(lua_State *luastate)
{
    lua_State *l = luastate;
    if (lua_isinteger(l, 1) == 0)
    {
        lua_pushinteger(l, -1);
        return 1;
    }

    int fd = lua_tointeger(l, 1);
    sunnet::inst->close_conn(fd);

    // ???
    // 是否需要调用 on_socket_close 方法?

    lua_pushinteger(l, 0);
    return 1;
}